/* globals describe, beforeEach, $fixture, qq, assert, it */
describe("drag and drop", function () {
  "use strict";

  // For IE, from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill
  var includesPolyfill = function(searchElement, fromIndex) {

    // 1. Let O be ? ToObject(this value).
    if (this == null) {
      throw new TypeError("'this' is null or not defined");
    }

    var o = Object(this);

    // 2. Let len be ? ToLength(? Get(O, "length")).
    /* jshint -W016 */
    var len = o.length >>> 0;

    // 3. If len is 0, return false.
    if (len === 0) {
      return false;
    }

    // 4. Let n be ? ToInteger(fromIndex).
    //    (If fromIndex is undefined, this step produces the value 0.)
    var n = fromIndex | 0;

    // 5. If n ≥ 0, then
    //  a. Let k be n.
    // 6. Else n < 0,
    //  a. Let k be len + n.
    //  b. If k < 0, let k be 0.
    var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

    function sameValueZero(x, y) {
      return x === y || (typeof x === "number" && typeof y === "number" && isNaN(x) && isNaN(y));
    }

    // 7. Repeat, while k < len
    while (k < len) {
      // a. Let elementK be the result of ? Get(O, ! ToString(k)).
      // b. If SameValueZero(searchElement, elementK) is true, return true.
      // c. Increase k by 1.
      if (sameValueZero(o[k], searchElement)) {
        return true;
      }
      k++;
    }

    // 8. Return false
    return false;
  };

  var createChromeDragEvent = function(overrides) {
    return qq.extend({
      type: "dragover",
      dataTransfer: {
        effectAllowed: "all",
        files: [],
        items: [],
        types: []
      }
    }, overrides, true);
  };

  var createFirefoxDragEvent = function(overrides) {
    return qq.extend({
      type: "dragover",
      dataTransfer: {
        effectAllowed: "all",
        files: [],
        items: [],
        types: []
      }
    }, overrides, true);
  };

  var createIeDragEvent = function(overrides) {
    var e = qq.extend({
      type: "dragover",
      dataTransfer: {
        effectAllowed: undefined, // This actually throws an error, but I'm not sure how to mock that
        files: [],
        items: undefined,
        types: []
      }
    }, overrides, true);

    e.dataTransfer.types.includes = undefined;
    e.dataTransfer.types.contains = includesPolyfill.bind(e.dataTransfer.types);

    return e;
  };

  it("determines non-file inputs as invalid drag candidates", function() {
    $fixture.append("<div id='fine-dropzone'></div>");
    var uploadDropZone = new qq.UploadDropZone({element: $fixture.find("#fine-dropzone")});

    // A mock event similar to the one generated by dragging plaintext into the browser
    var chromeTextDragEvent = createChromeDragEvent({
      dataTransfer: {
        items: [
          {
            kind: "string",
            type: "text/plain"
          },
          {
            kind: "string",
            type: "text/html"
          }
        ],
        types: [
          "text/plain",
          "text/html"
        ]
      }
    });

    var firefoxTextDragEvent = createFirefoxDragEvent({
      dataTransfer: {
        items: [
          {
            kind: "string",
            type: "text/_moz_htmlcontext"
          },
          {
            kind: "string",
            type: "text/_moz_htmlinfo"
          },
          {
            kind: "string",
            type: "text/html"
          },
          {
            kind: "string",
            type: "text/plain"
          }
        ],
        types: [
          "text/_moz_htmlcontext",
          "text/_moz_htmlinfo",
          "text/html",
          "text/plain"
        ]
      }
    });

    var ieTextDragEvent = createIeDragEvent({
      dataTransfer: {
        types: [
          "Text"
        ]
      }
    });

    assert(!uploadDropZone._testing.isValidFileDrag(chromeTextDragEvent), "Chrome text drag events should not be valid file drags");
    assert(!uploadDropZone._testing.isValidFileDrag(firefoxTextDragEvent), "Firefox text drag events should not be valid file drags");
    assert(!uploadDropZone._testing.isValidFileDrag(ieTextDragEvent), "IE text drag events should not be valid file drags");

  });

  it("determines file inputs as valid drag candidates", function() {
    $fixture.append("<div id='fine-dropzone'></div>");
    var uploadDropZone = new qq.UploadDropZone({element: $fixture.find("#fine-dropzone")});

    // A mock event similar to the one generated by dragging several files into the browser
    var chromeFileDragEvent = createChromeDragEvent({
      dataTransfer: {
        items: [
          {
            kind: "file",
            type: "image/jpeg"
          },
          {
            kind: "file",
            type: "text/html"
          },
          {
            kind: "file",
            type: ""
          },
          {
            kind: "file",
            type: "application/javascript"
          }
        ],
        types: [
          "Files"
        ]
      }
    });

    var firefoxFileDragEvent = createFirefoxDragEvent({
      dataTransfer: {
        items: [
          {
            kind: "file",
            type: "application/x-moz-file"
          },
          {
            kind: "file",
            type: "application/x-moz-file"
          },
          {
            kind: "file",
            type: "application/x-moz-file"
          },
          {
            kind: "file",
            type: "application/x-moz-file"
          }
        ],
        types: [
          "application/x-moz-file",
          "Files"
        ]
      }
    });

    var ieFileDragEvent = createIeDragEvent({
      dataTransfer: {
        types: [
          "Files"
        ]
      }
    });

    assert(uploadDropZone._testing.isValidFileDrag(chromeFileDragEvent), "Chrome file drag events are valid file drags");
    assert(uploadDropZone._testing.isValidFileDrag(firefoxFileDragEvent), "Firefox file drag events are valid file drags");
    assert(uploadDropZone._testing.isValidFileDrag(ieFileDragEvent), "IE file drag events are valid file drags");
  });

  it("extracts directory path from entries", function() {
    var dnd = new qq.DragAndDrop();

    var entry = {
      name: "a.txt",
      fullPath: "/data/a.txt"
    };

    var directoryPath = dnd._testing.extractDirectoryPath(entry);

    assert.equal(directoryPath, "data/");
  });

  it("properly extracts directory path when file name occurs in parent directory names", function() {
    var dnd = new qq.DragAndDrop();

    var entry = {
      name: "data",
      fullPath: "/data/data"
    };

    var directoryPath = dnd._testing.extractDirectoryPath(entry);

    assert.equal(directoryPath, "data/");
  });
});
